package com.aaa.member.service.impl;


import com.aaa.common.constants.ExceptionConstant;
import com.aaa.common.constants.ReturnCode;
import com.aaa.common.util.CustomException;
import com.aaa.common.util.Result;
import com.aaa.member.entity.Client;
import com.aaa.member.entity.Logininfor;
import com.aaa.member.entity.MemberLevel;
import com.aaa.member.mapper.ClientMapper;
import com.aaa.member.service.ClientService;
import com.aaa.member.service.LogininforService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.Sha512Hash;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * (Client)表服务实现类
 *
 * @author liduo
 * @since 2020-11-17 18:40:02
 */
@Service("clientService")
public class ClientServiceImpl implements ClientService {
    @Resource
    private ClientMapper clientMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private LogininforService logininforService;

    @Autowired
    private HttpServletRequest request;

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public Result queryById(Integer id) {
        if (id == null) {
            throw new CustomException(ExceptionConstant.ID_NOT_NULL.getErrorCode(), ExceptionConstant.ID_NOT_NULL.getErrorMessage());
        }
        return new Result<>(ReturnCode.SUCCESS.getCode(), ReturnCode.SUCCESS.getMsg(), this.clientMapper.queryById(id));
    }

    /**
     * 查询多条数据
     *
     * @param offset 查询起始位置
     * @param limit  查询条数
     * @return 对象列表
     */
    @Override
    public Result queryAllByLimit(Integer offset, Integer limit) {
        if (offset == null || limit == null) {
            throw new CustomException(ExceptionConstant.INVALID_ARGUMENT.getErrorCode(), ExceptionConstant.INVALID_ARGUMENT.getErrorMessage());
        }
        return new Result<>(ReturnCode.SUCCESS.getCode(), ReturnCode.SUCCESS.getMsg(), this.clientMapper.queryAllByLimit(offset, limit));
    }

    /**
     * 新增数据
     *
     * @param
     * @return 实例对象
     */
    @Override
    public Result insert(String userName , String passWord) {

        if (userName == null || passWord ==null) {
            throw new CustomException(ExceptionConstant.INVALID_ARGUMENT.getErrorCode(), ExceptionConstant.INVALID_ARGUMENT.getErrorMessage());
        }
        Client client = new Client();
        client.setUsername(userName);
//盐值
        String salt = UUID.randomUUID().toString().substring(0,15);
//随机盐值，放入数据库
        client.setPwSalt(salt);
//获取用户输入的原始密码
//使用SHA512加密算法，把原始密码和随机到的盐值一起进行运算，得到密码，存入数据
//Sha512Hash(Object source, Object salt, int hashIterations)
//          第1个参数，原始密码，第2参数，随机盐值  第3参数 hash次数
//           和配置类中配置的加密算法名称和hash次数一致 com.aaa.sbms.config.ShiroConfig
        Sha512Hash sha512Hash = new Sha512Hash(passWord,salt,1024);
//设置参数
        client.setPassword(sha512Hash.toString());
        return new Result<>(ReturnCode.SUCCESS.getCode(), ReturnCode.SUCCESS.getMsg(), this.clientMapper.insert(client));

    }

    /**
     * 修改数据
     *
     * @param client 实例对象
     * @return 实例对象
     */
    @Override
    public Result update(Client client) {
        if (client == null) {
            throw new CustomException(ExceptionConstant.INVALID_ARGUMENT.getErrorCode(), ExceptionConstant.INVALID_ARGUMENT.getErrorMessage());
        }
        this.clientMapper.update(client);
        Integer clientId = (Integer) client.getId();
        return this.queryById(clientId);
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public Result deleteById(Integer id) {
        if (id == null) {
            throw new CustomException(ExceptionConstant.ID_NOT_NULL.getErrorCode(), ExceptionConstant.ID_NOT_NULL.getErrorMessage());
        }
        return new Result<>(ReturnCode.SUCCESS.getCode(), ReturnCode.SUCCESS.getMsg(), this.clientMapper.deleteById(id) > 0);
    }


    /**
    * 通过用户名查询用户信息
    *
     * 登录用户名和手机唯一性校验
    */

    @Override
    public Result queryClientByParam(String userNameOrPhoneNum) {
        Client client =  clientMapper.queryClientByParam(userNameOrPhoneNum);
        if (client!=null ){
            return  new Result<>(ReturnCode.FAIL.getCode(), ReturnCode.FAIL.getMsg(),client);
        }else {return  new Result<>(ReturnCode.SUCCESS.getCode(), ReturnCode.SUCCESS.getMsg(), null);}
    }


    /**
     * 用户登录并生成token放入redis
     * @param userNameOrPhoneNum
     * @param password
     * @return
     */
    @Override
    public Result userLogin(String userNameOrPhoneNum, String password) {
        //收集用户信息
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(userNameOrPhoneNum, password);
        //获取主体对象
        Subject currentUser = SecurityUtils.getSubject();
        //登录 执行认证的过程
        try {
            currentUser.login(usernamePasswordToken);
            Client client = (Client) currentUser.getPrincipal();
            //生成token值  String token= UUID.randomUUID().toString();
            String token = userNameOrPhoneNum + System.currentTimeMillis();
            client.setToken(token);
            //放入redis     3, TimeUnit.MINUTES  3分钟
            redisTemplate.opsForValue().set(token, client, 30, TimeUnit.DAYS);
            Map map = new HashMap<>();
            map.put("token", token);
            map.put("client", client);
            //登录日志记录
            loginInfoRecord(userNameOrPhoneNum,"0");
            return new Result<>(ReturnCode.SUCCESS.getCode(), ReturnCode.SUCCESS.getMsg(), map);
        } catch (AuthenticationException e) {
            e.printStackTrace();
            loginInfoRecord(userNameOrPhoneNum,"1");
        }
        return new Result<>(ExceptionConstant.ERROR_USERNAME_OR_PASSWORD.getErrorCode(), ExceptionConstant.ERROR_USERNAME_OR_PASSWORD.getErrorMessage(), null);
    }

    /**
     * 登录日志记录
     * @param userNameOrPhoneNum
     */
    private  void loginInfoRecord(String userNameOrPhoneNum,String isSuc){
        //登录成功添加登录日志
        Logininfor logininfor = new Logininfor();
        logininfor.setBrowser("mobile");
        if("0".equals(isSuc)){
            logininfor.setMsg("登录成功");
        }
        else{
            logininfor.setMsg("用户名或者密码错误");
        }

        //获取请求IP地址
        logininfor.setIpaddr(request.getRemoteAddr());
        logininfor.setLoginLocation("移动端登录");
        logininfor.setLoginName(userNameOrPhoneNum);
        logininfor.setOs("mobile");
        logininfor.setLoginTime(new Date());
        logininfor.setStatus(isSuc);
        logininforService.insert(logininfor);
    }

/**
 * 查询所有用户信息
 */

    @Override
    public   List<Client>  ListClient() {
        return clientMapper.ListClient();
    }

    @Override
    public int insertBy(Client client) {
       return clientMapper.insertBy(client);
    }
/**
 * 通过手机号修改密码
 */

    @Override
    public Result updateByPhoneNum(String PhoneNum , String passWord) {
        if (PhoneNum == null || passWord == null) {
            throw new CustomException(ExceptionConstant.INVALID_ARGUMENT.getErrorCode(), ExceptionConstant.INVALID_ARGUMENT.getErrorMessage());
        }
        Client client = new Client();
        client.setUsername(PhoneNum);
//盐值
        String salt = UUID.randomUUID().toString().substring(0, 15);
//随机盐值，放入数据库
        client.setPwSalt(salt);
//获取用户输入的原始密码
//使用SHA512加密算法，把原始密码和随机到的盐值一起进行运算，得到密码，存入数据
//Sha512Hash(Object source, Object salt, int hashIterations)
//          第1个参数，原始密码，第2参数，随机盐值  第3参数 hash次数
//           和配置类中配置的加密算法名称和hash次数一致 com.aaa.sbms.config.ShiroConfig
        Sha512Hash sha512Hash = new Sha512Hash(passWord, salt, 1024);
//设置参数
        client.setPassword(sha512Hash.toString());
        return new Result<>(ReturnCode.SUCCESS.getCode(), ReturnCode.SUCCESS.getMsg(), this.clientMapper.updateByPhoneNum(client));
    }

    /**
     * 查询指定行数据
     *
     * @param pageNo   查询起始位置
     * @param pageSize 查询条数
     * @param client
     * @return Result ---- Result.getData() 对象列表
     */
    @Override
    public Result queryAllByParam(Integer pageNo, Integer pageSize, Client client) {
        if (pageNo == 0 || pageSize == 0) {
            throw new CustomException(ExceptionConstant.INVALID_ARGUMENT.getErrorCode(),
                    ExceptionConstant.INVALID_ARGUMENT.getErrorMessage());
        }
        PageHelper.startPage(pageNo, pageSize);
        PageInfo<Client> pageInfo = new PageInfo<>(clientMapper.queryAll(client));

        return new Result<>(ReturnCode.SUCCESS.getCode(), ReturnCode.SUCCESS.getMsg(), pageInfo);
    }
}